/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.webanovare.ruzzle.mgr;

import com.webanovare.ruzzle.mgr.impl.IGame;
import com.webanovare.ruzzle.misc.Player;
import com.webanovare.ruzzle.misc.TimeSetting;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * handles the creation of games. It's also used by other classes such as beans 
 * for fetching games. Singleton.
 */
public class GameManager {
    private static GameManager theInstance;
    
    private Map<Integer, IGame> games;
    
    private PropertyChangeSupport observers;
    
    public static GameManager getInstance() {
        if(GameManager.theInstance == null) {
            GameManager.theInstance = new GameManager();
        }
        
        return GameManager.theInstance;
    }
    
    private GameManager() {
        this.games = new HashMap<Integer, IGame>();
    }
    
    /**
     * Will try to create a game for the given player.
     * @param gameOwner
     * @return True if the player isn't currently playing a game, otherwise false.
     */
    public int createGame(Player gameOwner, int size, TimeSetting time, String language) {
        if(this.isCurrentlyPlaying(gameOwner) != null) {
            return -1;
        }
        
        int id = this.generateGameId();
        this.games.put(id, Game.createInstance(gameOwner, size, time, id, language));
        
        //this.observers.firePropertyChange(Constants.PROP_GAME_CREATED, null, null);
        
        return id;
    }
    
    private int generateGameId() {
        Random r = new Random();
        int id = r.nextInt(Integer.MAX_VALUE);
        Logger.getAnonymousLogger().log(Level.INFO, id + "");
        return id;
    }
    
    /**
     * Will end a game that is owned by player p.
     * @param p
     * @return If the given player is an owner of a game, the game will be
     *         removed and true will be returned, otherwise false.
     */
    public boolean endGame(Player p) {
        IGame g = null;
        if((g = this.isCurrentlyPlaying(p)) != null) {
            this.games.remove(g.getGameId());
            return true;
        }
        return false;
    }
    
    public boolean endGame(int gameId) {
        if(this.games.containsKey(gameId)) {
            this.games.remove(gameId);
            return true;
        }
        return false;
    }
    
    /**
     * Will get the game that is played by player p.
     * @param p
     * @return the game that is played by the user
     * @throws IllegalStateException if the user isn't playing any game.
     */
    public IGame getGame(Player p) throws IllegalStateException {
        IGame g = this.isCurrentlyPlaying(p);
        
        return g;
    }
    
    public IGame getGame(int game) {
        return this.games.get(game);
    }
    
    public List<IGame> getGames() {
        List<IGame> gameList = new ArrayList<>();
        gameList.addAll(this.games.values());
        
        return gameList;
    }
    
    
    /**
     * Checks if a given user can create a game. If he can create a game,
     * this method will return null. If he can't create a game, this method
     * will return the game, that the user is currently playing.
     * @param p
     * @return 
     */
    private IGame isCurrentlyPlaying(Player p) {
        for(IGame g : this.games.values()) {
            if(g.getOwner().equals(p)) {
                return g;
            }
            
            Player opp = g.getOpponent();
            
            if(opp != null && g.getOpponent().equals(p)) {
                return g;
            }
        }
        
        return null;
    }
    
    public void addObserver(PropertyChangeListener observer) {
        this.observers.addPropertyChangeListener(observer);
    }
    
    
}
